#include "cloud_sync.h"
#include "object.h"
#include "amazon.h"
#include "object_dir.h"
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include "util.h"

#define QUEUE_MAX_LENGTH 10000

/* 
  The queue, of the form:
  0 ...>>... HEAD ...>>... TAIL ...>>... QUEUE_MAX_LENGTH
             |------------|  <- valid elements
  TAIL and HEAD shift towards right
  HEAD == TAIL => 0 element in the queue.
  HEAD == TAIL+1 => queue is full
  HEAD == TAIL-1 => 1 element in the queue
*/

static char *sync_queue;
/* Queue head and tail, that's all we need to protect */
static int q_head, q_tail;

/* Mutex which enables locking of queue */
static pthread_mutex_t mut;


void init_sync_queue () { 
  sync_queue = malloc (sizeof(char) * ID_STRING_LENGTH * QUEUE_MAX_LENGTH);
  q_head = q_tail = 0; 
  pthread_mutex_init (&mut, NULL);
}

void destroy_sync_queue () {
  pthread_mutex_destroy (&mut);
  free (sync_queue);
}

/*
  Popping something from Queue means shifting HEAD towards right 
  Assume buf has enough space for ID_STRING_LENGTH
  Returns 0 if everything OK, -1 if Queue is empty
*/
int pop_from_sync_queue (char *buf) {

  int ret = 0;

  pthread_mutex_lock (&mut);

  if (q_head != q_tail) { 
    memcpy (buf, sync_queue + (ID_STRING_LENGTH*q_head), ID_STRING_LENGTH);
    q_head = (q_head+1) % QUEUE_MAX_LENGTH;
  } else  /* Queue is full */
    ret = -1;

  pthread_mutex_unlock (&mut);

  return ret; 
}

/* 
  Pushing something means shifting tail towards right 
  Returns 0 if everything Ok, -1 if the queue is full
*/

int push_to_sync_queue (const char *object_name) {

  int ret = 0;

  pthread_mutex_lock (&mut);

  if (q_head != (q_tail+1) % QUEUE_MAX_LENGTH) {
    memcpy (sync_queue + (ID_STRING_LENGTH*q_tail), 
                                      object_name, ID_STRING_LENGTH);
    q_tail = (q_tail+1) % QUEUE_MAX_LENGTH;
  } else  /* queue is full */
    ret = -1;

  pthread_mutex_unlock (&mut);

  return ret;
}


void *sync_loop (void *unused_args) {

  char *list = malloc (ID_STRING_LENGTH*100000);
  while (1) {

    char object_name[ID_STRING_LENGTH];

    /* Fetching the list of all objects */
    int c = list_cloud_object ("", ID_STRING_LENGTH*100000, list);
    int i;
    for (i=0; i<c; i++) {
      add_to_object_dir (list + (i*ID_STRING_LENGTH));
      set_cloud_field (list + (i*ID_STRING_LENGTH), 1);
    }

    /* Syncing dirty disk cache */
    while (pop_from_sync_queue (object_name) == 0) {
      if (get_cloud_field (object_name) == 0) {
        debug ("Syncing %s\n", object_name);
        put_cloud_object (object_name);
      }
    }
    sleep (SLEEP_TIME);
  }
  free (list);
}


